// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef INTER_THREAD_COMM_H
#define INTER_THREAD_COMM_H

#include <deque>
#include <mutex>
#include <condition_variable>
#include "MemoryManagement/VmiBuffer.h"

class InterThreadComm {
public:
    /**
     * @brief: construct
     * @param [in] multiEnque: multiEnque
     * @param [in] multiDeque: multiDeque
     * @param [in] block: queue is blocked
     */
    InterThreadComm(bool multiEnque, bool multiDeque, bool block);

    /**
    * @brief: deconstruct
    */
    ~InterThreadComm();

    /**
     * @brief: put data into data queue
     * @param [in] packet: data
     */
    void PutPkt(const VmiBuffer& packet);

    /**
     * @brief: get a data from queue
     * @return : pointer of data packet, or nullptr if there are no data packet in the queue, caller need to check it
     */
    uint8_t* GetNextPkt();

    /**
     * @brief: get a data from queue with timeout
     * @param [in] timeoutMillis: unit is ms
     * @return : pointer of data packet, or nullptr if there are no data packet in the queue, caller need to check it
     */
    uint8_t* GetNextPktWait(int timeoutMillis);

    /**
     * @brief: get queue size
     * @return : number of items in the queue
     */
    size_t GetNumItems();

    /**
     * @brief: get total size
     * @return : total data size
     */
    uint32_t GetTotalSize();

    /**
     * @brief: If you want to release the communication object between threads, you should
     *         call this interface first, especially in blocking mode, and release the object
     *         after the blocked receiving thread exits.
     */
    void Cancel();

    /**
     * @brief: clear queue and free memory
     */
    void Clear();

private:
    uint32_t m_totalDataSize = 0;
    std::deque<uint8_t *> m_packetDeque = {};
    std::mutex m_lock = {};
    std::condition_variable m_conditionVariable = {};
    bool m_multiEnq;
    bool m_multiDeq;
    bool m_block;
    volatile bool m_status;
};

#endif
